﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KarlsTools;

namespace ImageProcessing
{
	public static class ConformalMappings
	{
		//args passed in double array
		// 

		public static double[, ,] Conformal1(double[, ,] adImage, int nImageWidth, int nImageHeight, double[] adParams, int nNumArgs)
		{
			if (nNumArgs <= 0)
				//error
				return null;
			double[,,] adOut;
			adOut = new double[nImageWidth,nImageHeight,3];
			double dMaxR = Math.Sqrt((double)nImageWidth * nImageWidth + (double)nImageHeight * nImageHeight) / 2;
			double xc = Math.Floor((double)nImageWidth / 2);
			double yc = Math.Floor((double)nImageHeight / 2);
			double n = adParams[0];
			double dx, dy;
			double r, theta;
			double du;
			double xp,yp;
			//Complex x,y,u,v;

			for (int j = 0; j < nImageHeight; j++)
			{
				for (int i = 0; i < nImageWidth; i++)
				{
					dx = (double)i - xc;
					dy = (double)j - yc;
					r = Math.Sqrt(dx * dx + dy * dy);
					theta = n * Math.Atan2(dy, dx);
					du = (Math.Pow((r / xc),(double)n)) * dMaxR;

					xp = Math.Floor(du * Math.Cos(theta)) + xc;
					yp = Math.Floor(du * Math.Sin(theta)) + yc;

					if (xp < 0) xp = 0;
					if (xp >= nImageWidth) xp = nImageWidth -1;
					if (yp < 0) yp = 0;
					if (yp >= nImageHeight) yp = nImageHeight - 1;

					adOut[i, j, 0] = adImage[(int)xp, (int)yp, 0];
					adOut[i, j, 1] = adImage[(int)xp, (int)yp, 1];
					adOut[i, j, 2] = adImage[(int)xp, (int)yp, 2];

				} //end for
			} //end for

			return adOut;
		}//end Conformal1

		public static double[, ,] ConformalComplex1(double[, ,] adImage, int nImageWidth, int nImageHeight, double[] adParams, int nNumArgs)
		{
			//z = (w - (k + i)) / (w - 1)
			if (nNumArgs <= 0)
				//error
				return null;

			double[, ,] adOut = new double[nImageWidth, nImageHeight, 3];;
			double[,,] adRaw = new double[nImageWidth,nImageHeight,2];
			double dHalfWidth = Math.Floor((double)nImageWidth / 2);
			double dHalfHeight = Math.Floor((double)nImageHeight / 2);
			double dX, dY;
			double xp, yp;
			
			Complex compW,compZ,compK;

			double minX = double.MaxValue;
			double minY = double.MaxValue;
			double maxX = double.MinValue;
			double maxY = double.MinValue;



			for (int j = 0; j < nImageHeight; j++)
			{
				for (int i = 0; i < nImageWidth; i++)
				{

					dX = (double)(i - (int)dHalfWidth) / nImageWidth;
					dY = (double)(j - (int)dHalfHeight) / nImageHeight;

					compW = new Complex(dX,dY);
					compK = new Complex(adParams[0], adParams[1]);
					//the transformation
					compZ = Complex.Divide(Complex.Subtract(compW, Complex.Add(compK,new Complex(0,1))), Complex.Subtract(compW, 1.0));

					xp = compZ.Real() * nImageWidth + dHalfWidth;
					yp = compZ.Imag() * nImageHeight + dHalfHeight;

					if (xp < minX) minX = xp;
					if (xp > maxX) maxX = xp;
					if (yp < minY) minY = yp;
					if (yp > maxY) maxY = yp;

					adRaw[i,j,0] = xp;
					adRaw[i,j,1] = yp;

				} //end for
			} //end for

			for (int j = 0; j < nImageHeight; j++)
			{
				for (int i = 0; i < nImageWidth; i++)
				{
					xp = Math.Floor((adRaw[i, j, 0] - minX) / (maxX - minX) * nImageWidth);
					yp = Math.Floor((adRaw[i, j, 1] - minY) / (maxY - minY) * nImageHeight);

					if (xp > 0 && xp < nImageWidth && yp > 0 && yp < nImageHeight)
					{
						adOut[i, j, 0] = adImage[(int)xp,(int)yp, 0];
						adOut[i, j, 1] = adImage[(int)xp, (int)yp, 1];
						adOut[i, j, 2] = adImage[(int)xp, (int)yp, 2];
					}//end if
					else
					{
						adOut[i, j, 0] = 0;
						adOut[i, j, 1] = 0;
						adOut[i, j, 2] = 0;
					} //end else
					
				} //end for
			} //end for


			return adOut;
		}//end ConformalComplex1


	}
}
